#!/usr/bin/perl -w
use strict;
use Mail::POP3Client;
use Net::SMTP::TLS;
use MIME::Lite;
use MIME::Parser;
use MIME::Base64;
use LWP;
use Data::Dumper;
use Config::General;
use Net::Twitter;
use Digest::MD5 qw(md5 md5_hex md5_base64);
my $conffile = "/home/theodore/.pet_gateway.rc";

# This is demo data for initial config
my $pet;
$pet->{twitter}->{oauth} = undef;
$pet->{email}->{user} = 'example@example.com';
$pet->{email}->{pass} = 'example_password';
$pet->{email}->{to} = 'email@example.com';
$pet->{timeout} = 60;
$pet->{pop3}->{server} = 'pop.example.com';
$pet->{pop3}->{port} = 111; 
$pet->{smtp}->{server} = 'smtp.example.com';
$pet->{smtp}->{port} = 111;

my %consumer_tokens = (
    consumer_key    => 'AYj0GGg1DWnxSUTXdkUX0w',
    consumer_secret => 'Vwjb1eAXjZiNony5eBcokv59cFHIwMOWlUgUGfqyY',
);

my $config; my $conf; #Setup config

eval{
	$config = new Config::General($conffile);
	my %get = $config->getall;
	$pet = \%get;
};
if ($@) {
	print "Config file not found or empty, creating...\n";
	$config = new Config::General;
	$config->save_file($conffile,$pet);
	die("Edit '$conffile' with your details\n");
}

my $parser = new MIME::Parser;
my $pop3 = new Mail::POP3Client( USER     => $pet->{email}->{user},
                              	PASSWORD => $pet->{email}->{pass},
                              	HOST     => $pet->{pop3}->{server},
                              	USESSL   => 1,
				PORT => $pet->{pop3}->{port},
                             );

my $smtp = Net::SMTP::TLS->new($pet->{smtp}->{server},
                           Hello   => 'my.mail.domain',
                           Timeout => $pet->{timeout},
			   Port    => $pet->{smtp}->{port}, #redundant
			   User    => $pet->{email}->{user},
			   Password=> $pet->{email}->{pass},
                          );

my $twit = Net::Twitter->new(
    traits => [qw/API::REST OAuth/], %consumer_tokens 
);

if (	not defined $pet->{twitter}->{oauth}
   ){

	my $auth_url = $twit->get_authorization_url;
	print " Authorize this application at: $auth_url\nThen, enter the PIN# provided to continue: ";

	my $pin = <STDIN>; # wait for input
	chomp $pin;

	my @access_tokens = $twit->request_access_token(verifier => $pin);
	$pet->{twitter}->{oauth} = \@access_tokens;
}
else {
	$twit->access_token($pet->{twitter}->{oauth}->[0]);
	$twit->access_token_secret($pet->{twitter}->{oauth}->[1]);
}


print "*** Checking for tweets ****************************************\n";
my @tweets;
my $timeline;
#get timeline
if (not defined $pet->{twitter}->{lastseen}->{timeline}) {
	$timeline = $twit->friends_timeline({count => 25});
}
else {
	$timeline = $twit->friends_timeline({since_id => $pet->{twitter}->{lastseen}->{timeline}});
}
if (defined $timeline->[0]->{id}) {
	$pet->{twitter}->{lastseen}->{timeline} = $timeline->[0]->{id};
	push(@tweets, @$timeline);
}

#get mentions
my $mentions;
if (not defined $pet->{twitter}->{lastseen}->{mentions}) {
	$mentions = $twit->mentions({count => 25});
}
else {
	$mentions = $twit->mentions({since_id => $pet->{twitter}->{lastseen}->{mentions}});
}
if (defined $mentions->[0]->{id}) {
	$pet->{twitter}->{lastseen}->{mentions} = $mentions->[0]->{id};
	push(@tweets, @$mentions);
}

#get direct_messages
my $direct_messages;
if (not defined $pet->{twitter}->{lastseen}->{direct_messages}) {
	$direct_messages = $twit->direct_messages({count => 25});
}
else {
	$direct_messages = $twit->direct_messages({since_id => $pet->{twitter}->{lastseen}->{direct_messages}});
}
if (defined $direct_messages->[0]->{id}) {
	$pet->{twitter}->{lastseen}->{direct_messages} = $direct_messages->[0]->{id};
	push(@tweets, @$direct_messages);
}

print "*** Sending tweets ****************************************\n";
for my $tweet (@tweets) {
	#email tweets
	my $hashkey = "";
	my $user = $tweet->{user};
	my $msg = MIME::Lite->new(
	    From     => "@".$user->{screen_name} ."<".$pet->{email}->{user}.">",
	    To       => "PET-Recipient<".$pet->{email}->{to}.">",
	    Subject  => $tweet->{text},
	    Type     => 'multipart/mixed',
	);
	#Make some text to help explain this email
	my $message = 
		"".$user->{name}." (".$user->{screen_name}.") at ".$tweet->{created_at}." said:\n\n".
		"".$tweet->{text}."\n\n".
		""."----------------------\n\n".
		""."To reply to this message, simply reply to this email, the username of the sender will automatically be added to the front of the message..\n".
#		""."If you wish to send a normal tweet, use the latest email with your hashkey.\n".
		""."If this tweet referenced an image it will be included as an attachment.\n\n";
	#Make some metadata so PET can do something with it when its returned
	my $metadata =
		""."Metadata follows, do not alter this or it may have *UNINTENDED CONSEQUENCES*.\n\n".
		""."//tweetid//=".$tweet->{id}."//\n".
		""."//hashkey//=".$hashkey."//\n".
		""."//screen_name//=".$user->{screen_name}."//\n".
		"";
	#Attach the text
	$msg->attach(
	    Type     =>'TEXT',
	    Data     =>$message.$metadata,
	);
	#Attach the photo (if there is one)
	#$msg->attach(
	#    Type        =>'image/gif',
	#    Path        =>'aaa000123.gif',
	#    Filename    =>'logo.gif',
	#    Disposition => 'attachment'
	#);

	$smtp->mail('emailguy@your.mail.host');
	$smtp->to($pet->{email}->{to});
	$smtp->data();
	$smtp->datasend($msg->as_string);
	$smtp->dataend();
	
	print $tweet->{id}."\n";
}
$smtp->quit();

#Check for new messages
print "*** Checking for messages ****************************************\n";
for( my $i = 1; $i <= $pop3->Count(); $i++ ) {
	my @head = $pop3->Head( $i );
	next if $head[0] =~ m/Return-Path/; # Skip outgoing mails
	print "sending update $i\n";
	my @body = $pop3->Body($i);

	my $tweet;

	my $msg = $pop3->HeadAndBody( $i );
	my $entity = $parser->parse_data($msg);
#	print Dumper $entity;
	
	my $msgpath = "";
        if (exists $entity->{ME_Parts}->[0] and defined $entity->{ME_Parts}->[0]) {
                $msgpath = $entity->{ME_Parts}->[0]->{ME_Bodyhandle}->path;
        }
	else {
                $msgpath = $entity->{ME_Bodyhandle}->path;
	}
	
	#Open the text part of the message
        open BODY, $msgpath or die "open: $!";
	my @msgs = ();
        while (<BODY>) {
		push @msgs, $_;			
        }
	my $message = $msgs[0];
        close BODY;
	print $message;

	my $attach = "";
	if (exists $entity->{ME_Parts}->[1] and defined $entity->{ME_Parts}->[1]) {
		$attach = $entity->{ME_Parts}->[1]->{ME_Bodyhandle}->path;
	}

	my $url = undef;
	if ($attach =~ m/\.(jpg|gif|png|jpeg)$/ ) {
		$url = upload($attach);
		print ">>>>>>> $url *************\n";
	}
	$message .= " - $url" if defined $url;

	if ($pop3->Body($i) =~ m#//tweetid//=(.*)//#) {
		my $replyto = $1;
		print "replying to $replyto, ";
		if ($pop3->Body($i) =~ m#//screen_name//=(.*)//#) {
			my $screen_name = $1;
			print "$screen_name\n";
			$message = "@".$screen_name." ".$message;
		}
		if (length($message) > 140) {
			while (length($message > 140)) {
				my $short_message = substr($message,0,140);
				$message = substr($message,140);
				$tweet = $twit->update({status => $short_message, in_reply_to_status_id => $replyto});
			}
		} else {
			$tweet = $twit->update({status => $message, in_reply_to_status_id => $replyto});
		}
	}
	else {
		print "new tweet :";
		$tweet = $twit->update($message);
	}
	print "Sent: ".$tweet->{id}."\n";

	$pop3->Delete($i);
}
$pop3->Close();

##TODO##
##Check for and refresh expired hashkeys
#my $newhash = 0;
#if (not defined $pet->{hashkey} or not defined $pet->{hashkey}->[0]) {
#	#No hashkey, send a new one ASAP
#	$pet->{hashkey} = [&new_hashkey()];
#	$newhash = 1;
#}
#else {
#	my $hash = pop @{$pet->{hashkey}};
#	if ($hash->{refresh} > time) {
#		$hash = &new_hashkey;	
#		$newhash = 1;
#	}
#}

#$twit->update("hello".time);

$config->save_file($conffile,$pet);

exit(0);

sub new_hashkey {
	return {refresh => time + 21600, expires => time + 25200, hash => md5_base64(time)};
}

#THIS IS COPIED WHOLESALE FROM Image::Imgur on CPAN
# Available here: http://search.cpan.org/~ohwow/Image-Imgur-0.01/lib/Image/Imgur.pm
#Copied in to remove Moose requirement, and cause I'm lazy

sub upload {
	my $image_path = shift;
	my $res;
	if($image_path =~ /http:\/\//)	{
		$res = $image_path;
	} else {
		my $fh;
		open $fh,"<", $image_path or return -1;
		$res = _read_file($image_path);
	}
	$res = _upload($res);
	return $res;
}


# base64'd image
sub _read_file {
	my $fname = shift;
	my $fh;
	open $fh, "<", $fname or return -1;
	binmode $fh;
	return encode_base64(join("" => <$fh>));
}

sub _upload {
	my $image = shift;
	return undef unless($image);

	my $imgurl_api_key = "476c5cf3cd4aa59802f3f3a51de0956a";

	my $user_a = LWP::UserAgent->new(agent => "Perl");
	my $res = $user_a->post('http://imgur.com/api/upload.xml', ['image' => $image, 'key' => $imgurl_api_key ]);
	if($res->content =~ /<original_image>(.*?)<\/original_image>/)	{
		return $1;
	} elsif ($res->content =~ /<error_code>(\d+)<\/error_code>/) {
		return $1;
	} else {
		return -3;
	}
}




__END__
